home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TeX 1995 July
/
TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO
/
tex-k
/
tex-eplain-archive
/
000009_kb@cs.umb.edu_Sat Apr 16 12:21:34 1994.msg
< prev
next >
Wrap
Internet Message Format
|
1995-01-08
|
21KB
Received: from terminus.cs.umb.edu by cs.umb.edu with SMTP id AA25130
(5.65c/IDA-1.4.4 for <tex-eplain-exp@cs.umb.edu>); Sat, 16 Apr 1994 16:21:35 -0400
Received: by terminus.cs.umb.edu id AA29542
(5.65c/IDA-1.4.4 for tex-eplain); Sat, 16 Apr 1994 16:21:34 -0400
Date: Sat, 16 Apr 1994 16:21:34 -0400
From: "K. Berry" <kb@cs.umb.edu>
Message-Id: <199404162021.AA29542@terminus.cs.umb.edu>
To: tex-eplain@cs.umb.edu
Subject: indexing
Here's the indexing support I've been working on, if anyone is brave
enough to test it. The shar file has two files -- the tex source and the
beginnings of the documentation.
Comments are welcome.
#!/bin/sh
# This is a shell archive.
# Run the file through sh to extract its contents.
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# eidx.tex
# idx.texi
# This archive created: Sat Apr 16 16:19:33 1994
# By: ()
cat << \SHAR_EOF > eidx.tex
\input eplain
\catcode`@ = 11
% The index(es).
%
% \defineindex{PREFIX} defines an index with ``prefix'' PREFIX. The
% prefix is used to construct the output filename and the various
% commands. We just define all the index commands for this index to
% call the general commands with PREFIX.
%
\let\extraidxcmdsuffixes = \empty
%
\outer\def\defineindex#1{%
\def\@idxprefix{#1}%
%
% Define the indexing commands for this prefix.
\for\@idxcmd:=,marked,submarked,name%
\extraidxcmdsuffixes\do
{%
\@defineindexcmd\@idxcmd
}%
%
% Allocate a stream for the output.
\ece\innernewwrite{@#1indexfile}%
%
% And a conditional to test whether we've opened the file.
\ece\innernewif{if@#1indexfileopened}%
}%
%
%
% \@defineindexcmd{SUFFIX} defines both silent and non-silent index
% command for prefix \@idxprefix with suffix SUFFIX. That is, we define
% both `\@idxprefix dxSUFFIX' and `\s\@idxprefix dxSUFFIX' to call the
% corresponding generic command with \@idxprefix. \silentindexentry is
% used to decide whether we should ignore following spaces.
%
\newif\ifsilentindexentry
%
\def\@defineindexcmd#1{%
\@defineoneindexcmd{s}{#1}\silentindexentrytrue
\@defineoneindexcmd{}{#1}\silentindexentryfalse
}%
%
%
% \@defineoneindexcmd{PREFIX}{SUFFIX}{PRECALL} does just one silent or
% non-silent commands. We define the command `\@@PREFIXidxSUFFIX' to do
% PRECALL, then define \@idxprefix, then call \@idxgetrange with an
% argument of `\@@{,s}idxSUFFIX'. (So far every indexing command
% should allow a range. If not, you could redefine `\@@{,s}idxSUFFIX'
% after this macro is called.)
%
\def\@defineoneindexcmd#1#2#3{%
\toks@ = {#3}%
\edef\temp{%
\def
% We have to restrict expansion because the generic (\@@...)
% commands will be defined after the first call to \defineindex.
% Not expanding the user (\idx...) commands is unnecessary unless
% the user has defined some new commands, but may as well be cautious.
\expandonce\csname#1\@idxprefix dx#2\endcsname % e.g., \idx or \sidxname.
{\def\noexpand\@idxprefix{\@idxprefix}% define \@idxprefix
% call, e.g., \@@idx or \@@sidxname:
\expandonce\csname @@#1idx#2\endcsname
}%
\def
\expandonce\csname @@#1idx#2\endcsname{% e.g., \@@idx
% First do PRECALL.
\the\toks@
% Then call \@idxgetrange with, e.g., \@idx or \@sidxname as its arg.
\noexpand\@idxgetrange\expandonce\csname @#1idx#2\endcsname
}%
}%
\temp
}%
%
%
% \@idxwrite{TERM}{PAGENO} writes a general index entry for TERM on page
% PAGENO to the index file `\@idxprefix indexfile'. We open the stream
% as `\indexfilebasename.\@idxprefix dx' if it isn't already open.
%
\let\indexfilebasename = \jobname
%
\def\@idxwrite#1#2{%
% Be sure the file is opened.
\csname if@\@idxprefix indexfileopened\endcsname \else
\expandafter\immediate\openout\csname @\@idxprefix indexfile\endcsname =
\indexfilebasename.\@idxprefix dx
\expandafter\global\csname @\@idxprefix indexfileopenedtrue\endcsname
\fi
%
% Save the index term.
\def\temp{#1}%
%
% Write the index term and page number.
\edef\@wr{%
\expandafter\write\csname @\@idxprefix indexfile\endcsname{%
\string\indexentry
{\sanitize\temp}%
{\noexpand#2}%
}%
}%
\@wr
%
% Marginalize the index term, if desired.
\ifindexproofing \insert\@indexproof{\indexproofterm{#1}}\fi
%
% We just appended at least one non-discardable item (namely, the
% whatsit from the \write) to the current list. So in case glue comes
% next (not unlikely), be sure we don't inadvertently make that glue a
% valid breakpoint, if it wouldn't have been without us.
\hookrun{afterindexterm}%
%
% This is the end of the index entry processing. If this was a silent
% entry, ignore following spaces.
\ifsilentindexentry \expandafter\ignorespaces\fi
}%
%
%
% If this conditional is true, we output the index terms on the page
% where they occur.
\newif\ifindexproofing
%
% We need a new insertion class to collect the proofed terms.
\newinsert\@indexproof
\dimen\@indexproof = \maxdimen % No limit on number of terms.
\count\@indexproof = 0 \skip\@indexproof = 0pt % They take up no space.
%
% This actually typesets the proofed term. We don't go to any lengths
% to provide nice-looking output; since the term might have all kinds of
% weird characters in it, we just dump it in the smallest standard
% Computer Modern typewriter font.
%
% We put the term in an \hbox, even though that might make the output
% run off the page, since we don't really need to see all of it, and
% I think it's better to opt for simplicity -- one term per line.
\font\indexprooffont = cmtt8
\def\indexproofterm#1{\hbox{\strut \indexprooffont #1}}%
%
%
% If \output doesn't use \makeheadline, or redefines it, it's up to the
% new \output to call \indexproofunbox.
\let\@plainmakeheadline = \makeheadline
\def\makeheadline{%
\ifvoid\@indexproof\else \indexsetmargins \indexproofunbox \fi
\@plainmakeheadline
}%
%
% We want to put the proof index terms in the margin, outside the
% printed area. So if \outsidemargin (for odd pages) and \insidemargin
% (for even pages) are undefined, we define them (both) to be the default
% TeX margin -- one inch + \hoffset.
\def\indexsetmargins{%
\ifx\undefined\outsidemargin
\dimen@ = 1in
\advance\dimen@ by \hoffset
\edef\outsidemargin{\the\dimen@}%
\let\insidemargin = \outsidemargin
\fi
}%
%
% We always put the terms in the right-hand margin, so long terms run
% off the page, instead of into the text.
\def\indexproofunbox{%
\rlap{%
\kern\hsize
\ifodd\pageno \kern\outsidemargin \else \kern\insidemargin \fi
\vbox to 0pt{\unvbox\@indexproof\vss}%
}%
}%
%
%
% \@idxgetrange\CS parses an optional argument which, if present, should
% be either `begin' or `end', marking the beginning or ending of a range
% for the index entry. If we find this, we set the appropriate one of
% \@idxrangestr. Then we call \CS.
%
% If the optional argument is `see' or `seealso' we read another
% argument, namely, the entry to see.
%
\def\idxrangebeginword{begin}%
\def\idxbeginrangemark{(}% the corresponding magic char to go in the idx file
%
\def\idxrangeendword{end}%
\def\idxendrangemark{)}%
%
\def\idxseecmdword{see}%
\def\idxseealsocmdword{seealso}%
\newif\if@idxsee
\let\@idxseenterm = \relax
%
\def\idxpagemarkupcmdword{pagemarkup}%
\let\@idxpagemarkup = \relax
%
\def\@idxgetrange#1{%
\let\@idxrangestr = \empty
\let\@afteridxgetrange = #1%
\@getoptionalarg\@finidxgetopt
}%
\def\@finidxgetopt{%
\for\@idxarg:=\@optionalarg\do{%
% These are ordered by my guess at frequency of use.
\expandafter\@idxcheckpagemarkup\@idxarg=,%
%
\ifx\@idxarg\idxrangebeginword
\def\@idxrangestr{\idxencapoperator\idxbeginrangemark}%
\else
\ifx\@idxarg\idxrangeendword
\def\@idxrangestr{\idxencapoperator\idxendrangemark}%
\else
\ifx\@idxarg\idxseecmdword
\def\@idxpagemarkup{indexsee}%
\@idxseetrue
\else
\ifx\@idxarg\idxseealsocmdword
\def\@idxpagemarkup{indexseealso}%
\@idxseetrue
\else
\ifx\@idxpagemarkup\relax
\errmessage{Unrecognized index option `\@idxarg'}%
\fi
\fi
\fi
\fi
\fi
}%
\@afteridxgetrange
}%
%
%
% Check for a command of the form `pagemarkup=\cmd', and if found, set
% \@idxpagemarkup to `cmd'.
%
\def\@idxcheckpagemarkup#1=#2,{%
\def\temp{#1}%
\ifx\temp\idxpagemarkupcmdword
\if ,#2, % If #2 is empty, complain.
\errmessage{Missing markup command to `pagemarkup'}%
\else
% Remove a trailing =.
\def\temp##1={##1}%
\edef\@idxpagemarkup{\temp\string#2}%
\fi
\fi
}%
%
%
% \@idxtokscollect uses \@idxmaintoks as the token list for the main
% part of an index entry and \@idxsubtoks for the subpart. Then it
% calls \@idxwrite.
%
\def\idxsubentryseparator{!}%
\def\idxencapoperator{|}%
\def\idxmaxpagenum{99999}%
%
\newtoks\@idxmaintoks
\newtoks\@idxsubtoks
%
\def\@idxtokscollect{%
% Remember the subentry.
\edef\temp{\the\@idxsubtoks}%
%
% We want to expand the conditions, but not the terms. The index
% entry starts simply with \@idxmaintoks and \@idxsubtoks.
\edef\@indexentry{%
\the\@idxmaintoks
\ifx\temp\empty\else \idxsubentryseparator\the\@idxsubtoks \fi
\@idxrangestr
}%
%
% If this is a `see' or `see also' entry, we need to read one more
% arg. We use a giant page number so the entry will be last (for the
% benefit of `see also's). MakeIndex rejects page numbers >=1000.
%
\if@idxsee
\@idxseefalse % Reset so the next term won't be a `see'.
\edef\temp{\noexpand\@finidxtokscollect{\idxmaxpagenum}}%
\else
\def\temp{\@finfinidxtokscollect\folio}%
\fi
\temp
}%
%
%
% \@finidxtokscollect{PAGENO}{REAL-TERM} reads the final term for
% see/see also entries. We do not check if the person has put both a
% range and a see in the same index term (which will confuse makeindex).
%
\def\@finidxtokscollect#1#2{%
\def\@idxseenterm{#2}%
\@finfinidxtokscollect{#1}%
}%
%
% \@finfinidxtokscollect{PAGENO} writes \@indexentry for page PAGENO.
% Besides \@indexentry, if \@idxpagemarkup is not \relax we output an
% index entry \@indexentry|\@idxpagemarkup{PAGENO}. And if
% \@idxseenterm is not \relax we output {\@idxseenterm} after the
% \@idxpagemarkup. (This will become an argument to the ``markup''
% command, which will be \indexsee or \indexseealso.)
%
\def\@finfinidxtokscollect#1{%
% If we've got a page markup command, append it.
\ifx\@idxpagemarkup\relax \else
\toks@ = \expandafter{\@indexentry}%
\edef\@indexentry{\the\toks@ \idxencapoperator \@idxpagemarkup}%
\let\@idxpagemarkup = \relax
\fi
%
% If we've got an argument to the ``page markup'' command, append it.
\ifx\@idxseenterm\relax \else
\toks@ = \expandafter{\@indexentry}%
\edef\@indexentry{\the\toks@{\sanitize\@idxseenterm}}%
\let\@idxseenterm = \relax
\fi
%
% Finally, write what we've constructed.
\expandafter\@idxwrite\expandafter{\@indexentry}{#1}%
}%
%
%
% \@idxcollect{MAIN}{SUB} sets up the token registers
% \@idx{main,sub}toks, then calls \@idxtokscollect. This is convenient
% for some of the macros below.
%
\def\@idxcollect#1#2{%
\@idxmaintoks = {#1}%
\@idxsubtoks = {#2}%
\@idxtokscollect
}%
%
%
% Following are the TeX macros that correspond to the commands
% that actually appear in the document.
%
% \@idx{TERM} produces TERM in the output and then makes the index entry
% for TERM as usual. We don't allow a [SUBTERM] here since then we
% would lose spaces after the command, which would be very inconvenient.
%
% As with all our index commands, we've already defined \@idxprefix (in
% \idx or whatever), to save passing it around, and we've looked for a
% range argument before TERM.
%
\def\@idx#1{%
#1% Produce TERM as output.
\@idxcollect{#1}{}%
}%
%
% \@sidx{TERM}[SUBTERM] produces an index entry TERM and no output. If
% SUBTERM is present, this is a subentry. (At the moment, I don't
% provide for subsubentries, since I've never needed that.)
%
\def\@sidx#1{\@idxmaintoks = {#1}\@getoptionalarg\@finsidx}%
\def\@finsidx{%
\@idxsubtoks = \expandafter{\@optionalarg}%
\@idxtokscollect
}%
%
%
% \@idxconstructmarked{TOKS-REG}\CS{TERM}
%
\def\idxsortkeysep{@}% This `@' is catcode 11, but it doesn't matter.
%
\def\@idxconstructmarked#1#2#3{%
\toks@ = {#2}% The control sequence.
\toks2 = {#3}% The term.
%
% Construct TERM@\CS{TERM} as the string to write.
\edef\temp{\the\toks2 \idxsortkeysep \the\toks@{\the\toks2}}%
%
% Save it in TOKS-REG.
#1 = \expandafter{\temp}%
}%
%
%
% \@idxmarked\CS{TERM} outputs \CS{TERM} and then calls the main part of
% \@sidxmarked.
%
\def\@idxmarked#1#2{%
#1{#2}% Produce \CS{TERM} as output.
\@idxconstructmarked\@idxmaintoks{#1}{#2}%
\@idxsubtoks = {}%
\@idxtokscollect
}%
%
% \@sidxmarked\CS{TERM}[SUBTERM] outputs an index entry sorted by TERM
% but producing \CS{TERM}.
%
\def\@sidxmarked#1#2{%
\@idxconstructmarked\toks@{#1}{#2}%
\edef\temp{{\the\toks@}}%
\expandafter\@sidx\temp
}%
%
%
% \@idxsubmarked{TERM}\CS{SUBTERM} is like \@idxmarked, except that it's
% SUBTERM that's marked instead of TERM.
%
\def\@idxsubmarked#1#2#3{%
#1 #2{#3}% produce `TERM \CS{SUBTERM} as output.
\@sidxsubmarked{#1}{#2}{#3}%
}%
%
% \@sidxsubmarked{TERM}\CS{SUBTERM} is to \@sidxmarked as \@idxsubmarked
% is to \@idxmarked.
%
\def\@sidxsubmarked#1#2#3{%
\@idxmaintoks = {#1}%
\@idxconstructmarked\@idxsubtoks{#2}{#3}%
\@idxtokscollect
}%
%
%
% \@idxcollectname{FIRST}{LAST} puts `LAST, FIRST' into \temp. (Well,
% we use \idxnameseparator instead of hardwiring `, '.) If FIRST is
% empty, don't include the separator.
%
\def\idxnameseparator{, }% as in `Tachikawa, Elizabeth'
%
\def\@idxcollectname#1#2{%
\def\temp{#1}%
\ifx\temp\empty
\toks@ = {}%
\else
\toks@ = {\idxnameseparator #1}%
\fi
\toks2 = {#2}%
%
\edef\temp{\the\toks2 \the\toks@}%
}%
%
%
% \@idxname{FIRST}{LAST} also produces `FIRST LAST' in the output and an
% index entry for `LAST, FIRST'.
%
\def\@idxname#1#2{%
#1 #2% Separate the names by a space in the output.
\@idxcollectname{#1}{#2}%
\expandafter\@idxcollect\expandafter{\temp}{}%
}%
%
% \@sidxname{FIRST}{LAST}[SUBTERM] is to \@sidx as \@idxname is to
% \@idx.
%
\def\@sidxname#1#2{%
\@idxcollectname{#1}{#2}%
\expandafter\@sidx\expandafter{\temp}%
}%
%
%
% Now we come to actually producing the index, i.e., implementing the
% formatting commands that MakeIndex outputs.
%
% \readindexfile is responsible for formatting and printing the index.
% It reads \indexfilebasename.ind. We implement the same commands that
% LaTeX does. I suppose we could allow for different indices having
% different basenames, but I can't imagine when that would be useful.
%
\let\indexfonts = \relax
\def\readindexfile#1{%
\edef\@idxprefix{#1}%
%
% Does the output file exist?
\testfileexistence[\indexfilebasename]{\@idxprefix nd}%
\iffileexists \begingroup
\indexfonts
%
% If no \begin or \end, define them. The argument will be `{theindex}'.
\ifx\begin\undefined
\def\begin##1{\@beginindex}%
\let\end = \@gobble
\fi
%
% Set up the default formatting:
\doublecolumns
\parindent = 0pt
%
% Let the user override the defaults.
\hookrun{beginindex}%
%
% Read the file:
\input \indexfilebasename.\@idxprefix nd
%
% \doublecolumns isn't affected by groups.
\singlecolumn
\endgroup
\else
\message{No index file \indexfilebasename.\@idxprefix nd.}%
\fi
}%
%
% Here's the default for `\begin{theindex}', if \begin isn't defined.
\def\@beginindex{%
\let\item = \@indexitem
\let\subitem = \@indexsubitem
\let\subsubitem = \@indexsubsubitem
}%
%
% \indexspace appears between groups in the ind file.
\let\indexspace = \bigbreak
%
% You can make \afterindexterm appear after the term and before the
% first page with the following in the ist file:
% delim_0 "\\afterindexterm "
% delim_1 "\\afterindexterm "
% delim_2 "\\afterindexterm "
\let\afterindexterm = \quad
%
%
% Top-level index entries start with \item.
\newskip\aboveindexitemskipamount \aboveindexitemskipamount = 0pt plus2pt
\def\aboveindexitemskip{\vskip\aboveindexitemskipamount}%
%
\def\@indexitem{\begingroup
\@indexitemsetup
\leftskip = 0pt
\aboveindexitemskip
\penalty-100 % Encourage page breaks before items.
%
% But forbid page breaks after items, in case a subitem follows.
\def\par{\endgraf\endgroup\nobreak}%
}%
%
% Secondary index entries.
\def\@indexsubitem{%
\@indexitemsetup
\leftskip = 1em
}%
%
% And tertiary entries.
\def\@indexsubsubitem{%
\@indexitemsetup
\leftskip = 2em
}%
%
% Common setup for the formatting.
\def\@indexitemsetup{%
\par
\hangindent = 1em
\raggedright
\hyphenpenalty = 10000
\hookrun{indexitem}%
}%
%
%
% \indexsee{TERM}{PAGENO} ignores PAGENO, and says `See TERM'.
\def\seevariant{\it}%
\def\indexseeword{See}%
\def\indexsee#1#2{{\seevariant \indexseeword\ }#1}%
%
% \indexseealso{TERM}{PAGENO} is similar.
\def\indexseealsowords{see also}%
\def\indexseealso#1#2{{\seevariant \indexseealsowords\ }#1}%
%
%
% We provide one index by default; commands are \idx, \sidx, etc.
\defineindex{i}%
SHAR_EOF
cat << \SHAR_EOF > idx.texi
@node Indexing
@section Indexing
@cindex indexing
@cindex sorting an index
@pindex makeindex
Eplain provides support for generating raw material for an index, and
for typesetting a sorted index. A separate program must do the actual
collection and sorting of terms, because @TeX{} itself has no support
for sorting. Eplain's indexing commands work with the program MakeIndex,
available by ftp from @samp{ftp.math.utah.edu} in
@file{pub/tex/makeindex}, and from the CTAN hosts in
@file{tex-archive/indexing/makeindex}; MakeIndex is also commonly
included in prepackaged @TeX{} distributions.
The basic strategy for indexing works like this:
@enumerate
@pindex .idx @r{files}
@item For a document @file{foo.tex}, Eplain's indexing commands (e.g.,
@code{\idx}; see the section `Indexing terms' below) write the raw index
material to @file{foo.idx}.
@pindex .ind @r{files}
@item MakeIndex reads @file{foo.idx}, collects and sorts the index, and
writes the result to @file{foo.ind}.
@item Eplain reads and typesets @file{foo.ind} on the next run of @TeX{}.
@end enumerate
@cindex multiple indices
@cindex indices, multiple
@findex defineindex
If your document needs more than one index, each must naturally have a
separate file. Therefore, Eplain provides the command
@code{\defineindex}, which takes an argument that is a single letter,
which replaces @samp{i} in the filenames and in the indexing command
names described below. For example,
@example
\defineindex@{m@}
@end example
@noindent will define the command @code{\mdx} to write to the file
@file{foo.mdx}. Eplain simply does @code{\defineindex@{i@}} to define
the default commands.
@menu
* Indexing commands:: Specifying what to index.
* MakeIndex interaction:: MakeIndex conventions followed by Eplain.
* Typesetting an index:: Printing the sorted output.
@end menu
@node Indexing commands
@subsection Indexing commands
@cindex indexing terms
@cindex indexing
\idx{term}
\sidx{term}[subterm]
\idxmarked\defn{term}
\sidxmarked\defn{term}[subterm]
\idxsubmarked{term}\defn{subterm}
\sidxsubmarked{term}\defn{subterm}
\idxname{First}{Last}
\sidxname{First}{Last}[subterm]
\idxnameseparator
\extraidxcmdsuffixes
\hookaction{afterindexterm}
\idxbeginrangemark [begin] -> (
\idxendrangemark [end] -> )
\indexseeword [see]
\indexseealsoword [seealso]
[pagemarkup=defn]
\idx{Ap-weight@$A_p$-weight}
@menu
* Proofing index terms:: Noting index entries where they're made.
@end menu
@node
@subsubsection Proofing index terms
\indexproofing{true,false}
\indexsetmargins
\outsidemargin
\insidemargin
\indexproofunbox
@node
@subsection MakeIndex interaction
\idxsubentryseparator
\idxencapoperator
\idxmaxpagenum
\afterindexterm
\item
\subitem
\subsubitem
@node Typesetting an index
@subsection Typesetting an index
\readindexfile{i}
\indexfilebasename
\indexfonts
\begin{theindex}...\end{theindex}
\hookaction{beginindex}
\aboveindexitemskip{,amount}
\hookaction{indexitem}
\indexspace
SHAR_EOF
# End of shell archive
exit 0